/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* define to prevent recursive inclusion -------------------------------------*/
#ifndef __X_LIST_H__
#define __X_LIST_H__

/* includes (standard library, system) ---------------------------------------*/
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <x_compiler.h>
/* includes (local) ----------------------------------------------------------*/

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/

/* double list */
typedef struct dlist {
    struct dlist *prev, *next;
} dlist_t;

/* single list */
typedef struct slist {
    struct slist *next;
} slist_t;

/* macro ---------------------------------------------------------------------*/

/**
 * DLIST_INIT - create a empty list head body
 */
#define DLIST_INIT(h) {&(h), &(h)}

/**
 * DLIST_DEF - define a empty list head
 */
#define DLIST_DEF(name) dlist_t name = DLIST_INIT(name)

/**
 * __dlist_foreach - iterate over a list
 * @pos:  the pointer to the dlist_t node to use as a loop cursor
 * @head: the pointer to your list head
 * @dir:  iterate direction, next for forward, prev for backward
 */
#define __dlist_foreach(pos, head, dir) for (pos = (head)->dir; pos != (head); pos = pos->dir)

/**
 * dlist_foreach - iterate over a list
 * @pos:  the pointer to the dlist_t node to use as a loop cursor
 * @head: the pointer to your list head
 */
#define dlist_foreach(pos, head) __dlist_foreach(pos, head, next)

/**
 * dlist_foreach_backward - iterate over a list backwards
 * @pos:  the pointer to the dlist_t node to use as a loop cursor
 * @head: the pointer to your list head
 */
#define dlist_foreach_backward(pos, head) __dlist_foreach(pos, head, prev)

/**
 * __dlist_for_each_safe - iterate over a list safe against removal of list entry
 * @pos:    the pointer to the dlist_t node to use as a loop cursor
 * @n:      the next pointer to the dlist_t node to use as temporary storage
 * @head:   the pointer to your list head
 * @dir:    iterate direction, next for forward, prev for backward
 *
 * note: If you need to modify the structure of the list while traversing the
 * list (for example, reconnecting nodes, inserting or deleting nodes),
 * __dlist_foreach_safe provides a safe way to avoid "empty dangling pointers"
 * or "list breaks" during traversal.
 */
#define __dlist_foreach_safe(pos, n, head, dir)                                                    \
    for (pos = (head)->dir, n = pos->dir; pos != (head); pos = n, n = n->dir)

/**
 * dlist_for_each_safe - iterate over a list safe against removal of list entry
 * @pos:    the pointer to the dlist_t node to use as a loop cursor
 * @n:      the next pointer to the dlist_t node to use as temporary storage
 * @head:   the pointer to your list head
 */
#define dlist_foreach_safe(pos, n, head) __dlist_foreach_safe(pos, n, head, next)

/**
 * list_for_each_safe_backward - iterate over a list safe against removal
 *                               of list entry backwards
 * @pos:    the pointer to the dlist_t node to use as a loop cursor
 * @n:      the next pointer to the dlist_t node to use as temporary storage
 * @head:   the pointer to your list head
 */
#define dlist_foreach_safe_backward(pos, n, head) __dlist_foreach_safe(pos, n, head, prev)

/**
 * dlist_foreach_entry - iterate over a list of given type
 * @i:      the pointer to structure that contains the dlist_t node, to use as a loop cursor
 * @n:      the next pointer to same structure, to use  as temporary storage
 * @head:   the pointer to your list head
 * @t:      the type of the container struct this is embedded in
 * @m:      the name of the member within the struct
 *
 * return: NA
 */
#define dlist_foreach_entry_safe(i, n, head, t, m)                                                 \
    for (i = container_of((head)->next, t, m), n = container_of((i->m).next, t, m);                \
         &(i->m) != (head); i = n, n = container_of((i->m).next, t, m))

#define dlist_foreach_entry(i, head, t, m)                                                         \
    for (i = container_of((head)->next, t, m); &(i->m) != (head);                                  \
         i = container_of((i->m).next, t, m))

/* inlines -------------------------------------------------------------------*/

/**
 * dlist_init - initialize a list head
 * @head: the list head to initialize
 *
 * return: NA
 */
static __always_inline void dlist_init(dlist_t *head)
{
    head->prev = head->next = head;
}

/**
 * __dlist_add_at - insert a new entry between two known consecutive entries
 *
 * This is only for internal list manipulation where we know
 * the prev/next entries already!
 */
static __always_inline void __dlist_add_at(dlist_t *prev, dlist_t *next, dlist_t *node)
{
    node->prev = prev;
    node->next = next;
    prev->next = node;
    next->prev = node;
}

/**
 * dlist_add - add a new entry at the front of the list
 * @head: list head to add in
 * @node: the node to be added
 *
 * Insert a new entry after the specified head
 * This is good for implementing stacks
 */
static __always_inline void dlist_add(dlist_t *head, dlist_t *node)
{
    __dlist_add_at(head, head->next, node);
}

/**
 * dlist_add_tail - add a new entry at the tail of the list
 * @head: list head to add in
 * @node: the node to be added
 *
 * Insert a new entry before the specified head
 * This is useful for implementing queues
 */
static __always_inline void dlist_add_tail(dlist_t *head, dlist_t *node)
{
    __dlist_add_at(head->prev, head, node);
}

/**
 * dlist_del - deletes entry from list.
 * @node: the node to be deleted
 *
 * Note: dlist_empty() on the node does not return true after this, the entry is
 * in an undefined state
 */
static __always_inline void dlist_del(dlist_t *node)
{
    node->prev->next = node->next;
    node->next->prev = node->prev;
}

/**
 * dlist_del - deletes entry from list and init it.
 * @node: the node to be deleted
 *
 * Note: dlist_empty() on the node return true after this
 */
static __always_inline void dlist_del_init(dlist_t *node)
{
    dlist_del(node);
    dlist_init(node);
}

/**
 * dlist_empty - check if a list is empty
 * @head: the list head to check
 */
static __always_inline int dlist_empty(dlist_t *head)
{
    return head->prev == head;
}

/* externs -------------------------------------------------------------------*/

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __X_LIST_H__ */
